/*
 * Copyright (c) 2009 by unreserved.org.
 * All rights reserved.
 */

package org.unreserved.ladderplot;

import java.io.*;
import java.util.*;
import org.apache.log4j.Logger;

/**
 * In-memory representation of a rendered LadderPlot. It consists of a
 * list of {@link TextLine TextLines}.
 */
public class TextCanvas {
    private static final Logger logger = Logger.getLogger(TextCanvas.class);
    
    private static final char[] NEWLINE = System.getProperty("line.separator", "\n").toCharArray();
    
    /**
     * Max number of chars per line. -1 means no limit. If the line
     * length is limited attempts to write beyond the end of the line
     * will be ignored or will result in truncation.
     */
    protected int maxWidth = 80;
    protected ArrayList<TextLine> lines = new ArrayList<TextLine>(200);
    // callback so that ModelTextRenderer can draw player lines on new lines
    protected ModelTextRenderer modelRenderer;
    
    public TextCanvas(ModelTextRenderer modelRenderer) {
        this.modelRenderer = modelRenderer;
        newline();
    }
    
    public void print(int linenum, int col, String s) {
        //logger.debug("print: linenum=" + linenum + " col=" + col);
        final int mincols = col + s.length();
        TextLine line = getLine(linenum, mincols);
        line.write(s, col);
    }
    
    public void print(int col, String s) {
        print(lines.size(), col, s);
    }
    
    private void print(char[] ca, int col, String s) {
        for (int i = 0; i < s.length(); i++) {
            final int pos = col + i;
            if (pos < 0) {
                logger.debug("print: truncating, pos=" + pos);
                continue;
            } if (pos > ca.length) {
                logger.debug("print: truncating, pos=" + pos);
                return;
            }
            ca[pos] = s.charAt(i);
        }
        //logger.debug("print: on exit: " + new String(ca));
    }
    
    public void newline() {
        TextLine line = new TextLine(80, -1);
        lines.add(line);
        modelRenderer.newline(line);
    }
    
    public int numLines() {
        return lines.size();
    }
    
    /**
     * Returns the line with the specified index.
     * 
     * @throws IndexOutOfBoundsException if linenum does not specify
     * an existing line
     */
    public TextLine getLine(int linenum, int mincols) {
        while (linenum >= numLines()) {
            newline();
        }
        return lines.get(linenum);
    }
    
    public void print(Writer out) throws IOException {
        logger.debug("print: #lines=" + numLines());
        for (TextLine line : lines) {
            line.write(out);
            out.write(NEWLINE);
        }
    }
    
    public String toString() {
        CharArrayWriter out = new CharArrayWriter(8192);
        try {
            print(out);
        } catch (IOException ex) {
            logger.warn("ignoring exception", ex);
        }
        return out.toString();
    }
}
